package com.cskaoyan.javase.oop1._2reference;
/**
 * 重新认识引用数据类型
 * 我们第一次认识和了解引用数据类型是在数组这一章节
 * 我们通过JVM内存模型图和数组的初始化过程，知道：
 * 一个引用数据类型变量，分为两个部分：
 *      1.在栈上创建引用，它是一个局部变量。
 *      2.在堆上开辟空间，创建对象。
 * 栈上的引用通过存储堆上对象的地址和对象产生联系。
 * 对象是引用数据类型的实质，但我们只能通过栈上引用间接访问堆上对象。
 * 现在，我们已经学习过对象与类的知识点了，是时候进一步或者换一个角度去了解引用数据类型了。
 *
 * 像数组那样理解引用数据类型
 *      虽然看到了引用数据类型的实质，但也把基本数据类型和引用数据类型完全割裂了。
 * 这两种数据类型当然不可能是完全没有关系的了！
 * 所以，我们需要让它们重新产生联系起来！
 *
 * 先回顾一下，在Java基础语法部分，我们给出的数据类型的概念/定义：
 *      数据类型：表示的是一组数据的集合，和基于该数据集合的一组合法操作。
 *      说白了,数据类型 = 数据 + 基于数据的操作
 * 这个定义套在基本数据类型上，实在再合适不过了。
 * 比如int类型，它的取值范围是固定的，有限的，能够做的操作（加减乘除等）也是被限制的。
 *
 * 那么这个定义能不能套在引用数据类型中呢？
 * 能否用数据类型的概念来统一基本数据类型和引用数据类型呢？
 *
 * 接下来我们需要分析一下，这个问题。
 * 在上一节类的定义中，类中的成员包括：
 *      1.成员变量
 *      2.成员方法
 * 成员变量本质上就是数据，成员方法本质上就是操作，那么假设做以下类比：
 *      1.数据的集合： 类中成员变量的集合
 *      2.操作的集合： 类中成员方法的集合
 *
 * 于是，就可以做出以下总结：
 *      一个类的定义，实际上就是定义了一种全新的数据类型，一种自定义的数据类型。
 *      这种完全不同于基本数据类型的数据类型，我们称之为"引用数据类型"。
 * 注：当然引用数据类型不仅仅包括类，但大体上上述说法是没问题的。
 *
 * 自定义的引用数据类型和基本数据类型是有区别的
 *      1.当我们在程序中使用一个基本数据类型时，由于基本数据类型是JVM当中已经预先定义好的
 *          （所以基本数据类型叫"内置数据类型"）
 * ，    JVM可以清楚的知道这个基本数据类型变量在内存中的存储方式（占用空间大小、结构等等）
 *       JVM能够正常开辟空间，正常给变量初始化赋值
 *
 * 但是类class这种引用数据类型，并不是内置数据类型，而是我们自定义的数据类型。
 * 那么如果我要使用一个类,希望通过类创建对象等等时
 * JVM怎么知道这个类当中有什么结构呢?
 *
 * 所以当我们需要在程序中使用某个类时,JVM就需要去了解和认识这个类型
 * 在Java当中,把JVM"认识,了解"一个类型的过程，称之为类加载。
 * 解释:
 *      1.关于类加载详细流程和步骤,后续课程中会详细解释,这里也不做详细解释
 *      2.JVM通过类加载,就可以做很多类型相关的操作了,就认识了解了这个类型.
 *      3.类加载是通过I/O流的形式,将类的class文件(字节码文件),读取进JVM内存中(方法区)
 *          然后通过一系列的操作
 *          JVM就认识了解该类型,就可以做类型相关的操作了.
 *          I/O流进行类加载的特点就是慢
 *
 *      思考:
 *          1.类加载是如何进行的呢?一个Java程序的执行,肯定会类加载大量的类
 *              那么程序员会在启动时,无脑的加载程序当中的所有类呢?
 *
 *              并不会,因为类加载的效率很低,如果无脑类加载,会导致程序的运行很慢
 *
 *          2.实际上,类加载是"懒加载"的,只有当必须,不得不进行类加载时,才会对一个类进行类加载
 *          3.当在程序中创建对象时,会不会进行类加载?
 *              肯定会,因为不类加载某个类,JVM不了解类型信息,是不可能创建对象的
 *
 *          4.创建对象和类加载两个过程,类加载在前在后呢?
 *              类加载在前,完成类加载之后,再进行创建对象
 *
 *          5.创建对象,一定会触发类加载,在Java中,我们把不得不进行类加载的场景,称之为"类加载的时机"
 *              当程序运行到"类加载的时机时"
 *              一定会先进行类加载,然后再进行相关的操作
 *              目前我们已经学习过的类加载时机:
 *                  a.new对象,new对象之前一定会类加载这个类
 *                  b.启动main方法.在main方法启动之前,一定会类加载装有main方法的类
 *
 *          6.类加载是懒加载,那么一个类的类加载有几次呢?一个类会不会类加载两次呢?
 *              在程序的某一次运行期间
 *              某个类的类加载要么不进行,要么至多进行一次
 *              注意:
 *              即便是再次碰到了类加载的时机,如何该类已经类加载过了,就不会再次类加载了!
 *
 * @since 15:58
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    // 在main方法启动之前,Demo类就已经类加载了!
    public static void main(String[] args) {
        System.out.println("hello world!");
        // 当代码运行到创建A对象的语句时,才会触发A类的类加载,类加载结束后,才会开始创建对象
        A a = new A();

        /*
            创建Demo对象是一种类加载的时机
            但是Demo类已经在启动main方法之前就已经类加载完毕了
            所以这里不会再次进行类加载了
          */
        Demo d = new Demo();
    }
}
class A{}
// B类和程序的运行没有任何关系,它不会进行类加载!
class B{}